﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.IO;

namespace RelationExpertSystem
{
    class PeopleFileParser
    {
        XmlWriterSettings _settings;

        public PeopleFileParser()
        {
            _settings = GetXmlWriterSettings();
        }

        public void Save(IEnumerable<Person> people, string path)
        {
            if (!Path.IsPathRooted(path))
                return;

            // if file exists, rename it
            string rename = null;
            if (File.Exists(path))
            {
                rename = path + ".temp";
                File.Move(path, rename);
            }

            using (XmlWriter writer = XmlWriter.Create(path, _settings))
            {
                writer.WriteStartDocument();
                writer.WriteStartElement("People");
                foreach (Person p in people)
                {
                    writer.WriteStartElement("Person");
                    writer.WriteElementString("Name", p.Name);
                    writer.WriteElementString("Sex", p.Sex.ToString());
                    if (!Person.IsNull(p.Father))
                        writer.WriteElementString("Father", p.Father.Name);
                    if (!Person.IsNull(p.Mother))
                        writer.WriteElementString("Mother", p.Mother.Name);
                    if (!Person.IsNull(p.Spouse))
                        writer.WriteElementString("Spouse", p.Spouse.Name);
                    writer.WriteEndElement();
                }
                writer.WriteEndElement();
                writer.WriteEndDocument();
            }

            if (rename != null)
                File.Delete(rename);
        }

        private XmlWriterSettings GetXmlWriterSettings()
        {
            XmlWriterSettings settings = new XmlWriterSettings();
            settings.Indent = true;
            settings.IndentChars = "  ";
            settings.NewLineChars = "\r\n";
            settings.NewLineHandling = NewLineHandling.Replace;
            return settings;
        }

        public IEnumerable<Person> Load(string path)
        {
            List<Person> people = new List<Person>();
            
            if (!Path.IsPathRooted(path) || !File.Exists(path))
                return null;

            using (XmlReader reader = XmlReader.Create(path))
            {
                int personLevel = 100;
                int level = 0;
                while (reader.Read())
                {
                    if (!reader.IsStartElement())
                    {
                        if (level == personLevel) // did we just finish a person?
                            people.Add(new Person(name, sex, father, mother, spouse));
                        level--;
                        continue;
                    }

                    level++;

                    switch (reader.Name)
                    {
                        case ("Person"): personLevel = level;  CreateNewPerson(people); break;
                        case ("Name"): reader.Read(); name = reader.Value; break;
                        case ("Sex"): reader.Read(); SetSex(reader.Value); break;
                        case ("Father"): reader.Read(); father = people.GetElement(reader.Value); break;
                        case ("Mother"): reader.Read(); mother = people.GetElement(reader.Value); break;
                        case ("Spouse"): reader.Read(); spouse = people.GetElement(reader.Value); break;
                    }
                }
            }

            return people;
        }

        private string name;
        private Sex sex;
        private Person father;
        private Person mother;
        private Person spouse;
        private void CreateNewPerson(List<Person> people)
        {
            name = null;
            sex = Sex.Male;
            father = null;
            mother = null;
            spouse = null;
        }

        private void SetSex(string value)
        {
            if (value == "Female")
                sex = Sex.Female;
            else
                sex = Sex.Male;
        }
    }
}
